using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace StupidSpaceThing
{
	internal class Camera
	{
		private GraphicsDevice device;

		private Vector3 position;
		public Vector3 Position { get { return position; } set { position = value; } }
		private Vector3 lookAt;
		public Vector3 LookAt { get { return lookAt; } }
		private Vector3 reference;
		public Vector3 Reference { get { return reference; } }

		private float aspectRatio;
		private float nearPlane;
		private float farPlane;
		private float fieldOfView;

		public readonly Matrix Projection;
		public Matrix View { get { return Matrix.CreateLookAt(Position, LookAt, Vector3.Up); } }

		private float yaw;
		public float Yaw { get { return yaw; } }
		private float pitch;
		public float Pitch { get { return pitch; } }

		public Vector3 RelativeLookAt { get { return lookAt - position; } }

		public Camera(GraphicsDevice device, Vector3 position, float yaw, float pitch) {
			this.device = device;
			this.position = position;

			reference = new Vector3(0,0,1);
			lookAt = reference + position;

			aspectRatio = (float)device.Viewport.Width / (float)device.Viewport.Height;

			nearPlane = 0.01f;
			farPlane = 180.0f;
			fieldOfView = 45.0f;

			this.yaw = yaw;
			this.pitch = pitch;

			Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(fieldOfView), aspectRatio, nearPlane, farPlane);
		}

		public void Rotate(float x, float y) {
			yaw += x;
			pitch += y;
			pitch = MathHelper.Clamp(pitch, -(float)(Math.PI / 2.0f - 0.1f), (float)(Math.PI / 2.0f - 0.1f));
			lookAt = Vector3.Transform(reference, Matrix.CreateRotationX(pitch) * Matrix.CreateRotationY(yaw)) + position;
		}
		
		private LinkedList<float> xRotations = new LinkedList<float>();
		private LinkedList<float> yRotations = new LinkedList<float>();
		public void RotateSmooth(float x, float y) {
			xRotations.AddFirst(x);
			yRotations.AddFirst(y);
			if( xRotations.Count > 8 ) {
				xRotations.RemoveLast();
				yRotations.RemoveLast();
			}
			float xTotal = 0.0f, yTotal = 0.0f;
			int totalCount = 0;
			int i = 0;
			foreach( float f in xRotations ) {
				xTotal += f * (xRotations.Count - i);
				i++;
				totalCount += i;
			}
			i = 0;
			foreach( float f in yRotations ) {
				yTotal += f * (yRotations.Count - i);
				i++;
			}
			float xAvg = xTotal / totalCount;
			float yAvg = yTotal / totalCount;
			Rotate(xAvg, yAvg);
		}

		public void Move(Vector3 moveVector) {
			position += moveVector;
			lookAt += moveVector;
		}
	}
}
